import json
import time
from datetime import datetime
import random

import redis
from django.contrib.auth.hashers import check_password

from django.shortcuts import render
from rest_framework.generics import ListCreateAPIView, GenericAPIView, RetrieveUpdateDestroyAPIView
from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin, RetrieveModelMixin
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler

from users.models import *
from users.serializers import *
from .tasks import send_message


class DepartmentView(ModelViewSet):
    queryset = Department.objects.all()
    serializer_class = DepartmentSer
    lookup_field = 'pk'
    #
    # # 添加一条部门
    # def post(self, request):
    #     name = request.data.get('name')
    #     num = Department.objects.filter(name=name).count()
    #     if num > 0:
    #         return Response({'code': 400, 'msg': '部门已存在'})
    #
    #     # 反序列化输入
    #     ser = DepartmentSer(data=request.data)
    #     if ser.is_valid():   # 校验数据是否有效 is_valid()外类怼特 返回布尔值 通过序列化器的三种校验方式
    #         ser.save()       # 存入数据库
    #
    #     return Response({'code': 200, 'msg': '部门添加成功', 'data': ser.data})
    #
    # # 修改部门信息
    # def put(self, request):
    #     id = request.data.get('id')
    #     name = request.data.get('name')
    #     dep = Department.objects.filter(id=id).first()
    #     if dep:
    #         # partial=True局部修改   instance要修改的对象   data 要修改的数据
    #         dep_ser = DepartmentSer(instance=dep, data={'name': name}, partial=True)
    #         dep_ser.is_valid(raise_exception=True)  # raise_exception 验证出错时，抛出异常信息
    #         dep_ser.save()
    #         return Response({'code': 200, 'msg': '部门数据修改成功', 'data': dep_ser.data})
    #     return Response({'code': 400, 'msg': '修改的数据不存在'})





class DutyView(ModelViewSet):
    queryset = Duty.objects.all()
    serializer_class = DutySer
    lookup_field = 'pk'

# 员工  视图集
class StaffAPIView(ModelViewSet):
    queryset = Staff.objects.all()
    serializer_class = StaffSer
    lookup_field = 'pk'






# 部门表 查询所有 添加一条
class Department_Lis_Add_APIView(APIView):
    # 查询所有部门
    def get(self, request):
        deps = Department.objects.all()
        ser = DepartmentSer(deps, many=True)
        return Response({'code': 200, 'msg': '加载部门成功', 'data': ser.data})

    # 添加一条部门
    def post(self, request):
        name = request.data.get('name')
        num = Department.objects.filter(name=name).count()
        if num > 0:
            return Response({'code': 400, 'msg': '部门已存在'})

        # 反序列化输入
        ser = DepartmentSer(data=request.data)
        if ser.is_valid():   # 校验数据是否有效 is_valid()外类怼特 返回布尔值 通过序列化器的三种校验方式
            ser.save()       # 存入数据库

        return Response({'code': 200, 'msg': '部门添加成功', 'data': ser.data})

    # 修改部门信息
    def put(self, request):
        id = request.data.get('id')
        name = request.data.get('name')
        dep = Department.objects.filter(id=id).first()
        if dep:
            # partial=True局部修改   instance要修改的对象   data 要修改的数据
            dep_ser = DepartmentSer(instance=dep, data={'name': name}, partial=True)
            dep_ser.is_valid(raise_exception=True)  # raise_exception 验证出错时，抛出异常信息
            dep_ser.save()
            return Response({'code': 200, 'msg': '部门数据修改成功', 'data': dep_ser.data})
        return Response({'code': 400, 'msg': '修改的数据不存在'})

# class Department_UP_DEL_APIView(APIView):

    # def put(self, request, pk):  # 修改部门信息
    #     name = request.data.get('name')
    #     dep = Department.objects.get(id=pk)
    #     if dep:
    #         data = request.data                        # 1 获取数据  
    #         dep_ser = DepartmentSer(dep, data=data)    # 2 创建序列化对象 
    #         dep_ser.is_valid(raise_exception=True)     # 3 进行验证    raise_exception 验证出错时，抛出异常信息
    #         dep_ser.save()                             # 4 保存数据          # 5 返回状态
    #         return Response({'code': 200, 'msg': '部门数据修改成功', 'data': dep_ser.data})
    #     return Response({'code': 400, 'msg': '修改的数据不存在'})

# 子视图
# class DutyAPIView(RetrieveUpdateDestroyAPIView):
#     queryset = Duty.objects.all()
#     serializer_class = DutySer
#     lookup_field = 'pk'

# # 混入扩展类
# class DutyAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
#     queryset = Duty.objects.all()
#     serializer_class = DutySer
#     lookup_field = 'pk'
#     # 查询所有职责
#     def get(self, request):
#         # duts = self.get_queryset()
#         # ser = self.get_serializer(duts, many=True)
#         # return Response({'code': 200, 'msg': '加载职责成功', 'data': ser.data})
#
#         return self.list(request)
#
#     # 添加职责
#     def post(self, request):
#         # name = request.data.get('name')
#         # num = Duty.objects.filter(name=name).count()
#         # if num > 0:
#         #     return Response({'code': 400, 'msg': '职责已存在'})
#         #
#         # # 反序列化输入
#         # ser = self.get_serializer(data=request.data)
#         # if ser.is_valid():   # 校验数据是否有效 is_valid()外类怼特 返回布尔值 通过序列化器的三种校验方式
#         #     ser.save()       # 存入数据库
#         #
#         # return Response({'code': 200, 'msg': '职责添加成功', 'data': ser.data})
#
#         return self.create(request)



# 生成短信验证码   请求容联云 发送短信  异步

# 生成短信验证码   请求容联云 发送短信  异步


class SmsView(APIView):  #  生成短信验证码
    def post(self, request):
        mobile = request.data.get('mobile')
        # uuid_ = request.data.get('uuid')
        if not all([mobile,]):
            return Response({'code': 400, 'error': '数据不完整'})

        # 2 生成短信验证码 并redis存储 方便验证
        sms_code = '%d' % random.randint(10000, 99999)
        redis_cli = redis.Redis()
        redis_cli.set(mobile, sms_code, ex=300)

        # 3 请求容联云 发送短信 .delay 异步执行任务
        res = send_message.delay(sms_code, mobile)

        return Response({'code': 200, 'msg': '短信已发送,注意查收!'})


        # if res:
        #     return Response({'code': 200, 'msg': '发送短信成功'})
        # else:
        #     return Response({'code': 400, 'msg': '发送短信失败'})



# 验证短信验证码  sms_code  code_id
class CheckSmsView(APIView):
    def post(self, request):
        sms_code = request.data.get('sms_code')
        uuid_ = request.data.get('code_id')

        # 查询redis 拿出存储的短信验证码stored_sms_code
        redis_cli = redis.Redis()
        stored_sms_code = redis_cli.get(uuid_)

        # 判断  存在&解码后=前端验证码
        if stored_sms_code and stored_sms_code.decode() == sms_code:
            return Response({'code': 200, 'msg': '对比成功'})
        else:
            return Response({'code': 400, 'error': '对比失败'})

# 账号登录
class LoginView(APIView):
    def post(self, request):
        username = request.data.get('username')
        password = request.data.get('password')
        try:
            user = User.objects.get(username=username)
        except Exception as e:
            print(e)
            return Response({'msg': '用户不存在'})
        pwd_bool = check_password(password, user.password)
        if pwd_bool:
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
            return Response({'msg': '登录成功', 'code': 200, 'user': {'username': user.username}, 'token': token})
        else:
            return Response({'msg': '密码错误', 'code': 400})


# 自定义的登录接口
class LogincountView(APIView):
    def post(self, request):
        # 1 接收前端数据
        username = request.data.get('username')
        password = request.data.get('password')
        mobile = request.data.get('mobile')
        smscode = request.data.get('code')

        # 2 数据基本校验 是否拿到值
        if not all([username, password,]):
            return Response({'code': 400, 'msg': '数据不完整'})

        # 3 判断用户是否第一次登陆 第一次登陆为注册
        user = User.objects.filter(username=username).first()
        redis_cli = redis.Redis(db=3)

        # 4 用户存在   登陆
        if user:
            # 校验密码  is_staff 管理员  is_active账号激活
            if check_password(password, user.password):  # 密码正确

                if user.is_staff and user.is_active:  # 具有权限
                    # 生成tokrn
                    token = self.gen_token(user)
                    user.last_login = datetime.now()
                    user.save()

                    # 获取用户当前 所有的权限
                    # 获取用户所有角色  # p ====> [('get ^users/permission/$',),(xxx), (xxx)]
                    roles = user.role.all()
                    permissions_list = []
                    for role in roles:
                        p = role.permission_set.all().values_list('code_name')
                        permissions_list += [i[0] for i in p]

                    # 权限去重
                    permission_list = list(set(permissions_list))

                    # 将权限存入redis
                    key = 'user_permissions_%s' % user.id
                    redis_cli.set(key, json.dumps(permissions_list))

                    return Response({
                        'code': 200, 'msg': '登陆成功,进入首页',
                        'username': user.username,
                        'uid': user.id,
                        'token': token
                    })
                # 没有权限
                return Response({'code': 400, 'msg': '没有权限'})
            else:   # 1 密码不正确   或    2 用户在重置密码
                if not all([username, password, mobile, smscode]):  # 存在手机号和验证码 说明 用户在重置密码
                    # 使用静态方法封装validate_code   返回布尔值
                    # stored_code = redis_cli.get(mobile)
                    # if stored_code and stored_code.decode()==smscode:
                    validate_sms_code = self.validate_code(redis_cli, mobile, smscode)
                    if validate_sms_code:

                        # 验证成功 set_password(password) 密文存储密码
                        user.set_password(password)
                        user.save()
                        return Response({'code': 207, 'msg': '密码已重置'})
                    else:
                        return Response({'code': 204, 'msg': '验证码过期或错误'})

                return Response({'code': 205, 'msg': '用户名或密码不正确'})


        # 5 用户不存在 注册  -- 验证短信验证码
        else:
            validate_sms_code = self.validate_code(redis_cli, mobile, smscode)
            if validate_sms_code:  # 短信验证通过  注册
                User.objects.create_user(username=username, password=password, phone=mobile)
                user.last_login = datetime.now()
                user.save()
                return Response({'code': 201, 'msg': '注册成功，需申请管理员权限'})
            else:   # 没有通过
                return Response({'code': 204, 'msg': '验证码过期或错误'})

    # 生成tokrn
    @staticmethod
    def gen_token(user):
        """
        定义生成token的函数
        :param user:
        :return token:
        """
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return token

    # 验证短信验证码
    @staticmethod
    def validate_code(redis_cli, mobile, smscode):
        """
        :param redis_cli: redis连接对象
        :param mobile:  用户手机号 用于获取短信验证码
        :param smscode: 前端输入的短信验证码
        :return Boolean:
        """
        stored_code = redis_cli.get(mobile)
        if stored_code and stored_code.decode() == smscode:
            return True
        else:
            return False

# 统计总人数
class CountUserView(APIView):
    def get(self, request):
        total_count= User.objects.all().count()
        return Response({'code': 200, 'total_count': total_count })

# 统计日增人数
class DayAddUserView(APIView):
    def get(self, request):
        date_ = time.strftime('%Y-%m-%d')
        total_count = User.objects.filter(date_joined__contains=date_).count()
        return Response({'code': 200, 'total_count': total_count})

# 统计日活人数
class DayLiveUserView(APIView):
    def get(self, request):
        date_ = time.strftime('%Y-%m-%d')
        total_count = User.objects.filter(last_login__contains=date_).count()
        return Response({'code': 200, 'total_count': total_count})

# 分页器
class Page(PageNumberPagination):
    page_size = 2
    max_page_size = 2
    page_query_param = 'page'             # 页数关键字
    page_size_query_param = 'pagesize'   # 每页显示数据的关键字

# 用户管理视图集
class UserInfoViewSet(ModelViewSet):
    queryset = User.objects.all()
    serializer_class = User_Serializer
    pagination_class = Page
    lookup_field = 'pk'
    lookup_url_kwarg = 'pk'

    # 修改用户信息  重写update方法  方案一 在视图逻辑自己写
    # 方案二 借助序列化器 在序列化器重写update方法
    def update(self, request, *args, **kwargs):
        try:
            user = self.get_object()
            user.username = request.data.get('username')
            user.set_password(request.data.get('password'))
            user.phone = request.data.get('phone')
            user.email = request.data.get('email')
            user.save()
        except:
            return Response({'code': 500, 'msg': '修改用户报错'})

        return Response({'code': 200, 'msg': '修改用户成功'})


    # 添加用户信息   重写create方法  方案一 在视图逻辑自己写
    # 添加用户信息   重写create方法  方案一 在视图逻辑自己写
    # def create(self, request, *args, **kwargs):
    #     try:
    #         User.objects.create_user(**request.data)
    #     except:
    #         return Response({'code': 500, 'msg': '创建用户报错'})
    #
    #     return Response({'code': 200, 'msg': '添加用户成功'})


# 权限(路由)视图集
class PermissionViewSet(ModelViewSet):
    queryset = Permission.objects.all()
    serializer_class = Permission_Serializer


# 权限类型视图集
class PermissionTypeViewSet(ModelViewSet):
    queryset = PermissionType.objects.all()
    serializer_class = PermissionType_Serializer












